﻿' ******************************************************************************
' ** 
' **  Yahoo! Managed
' **  Written by Marius Häusler 2011
' **  It would be pleasant, if you contact me when you are using this code.
' **  Contact: YahooFinanceManaged@gmail.com
' **  Project Home: http://code.google.com/p/yahoo-finance-managed/
' **  
' ******************************************************************************
' **  
' **  Copyright 2011 Marius Häusler
' **  
' **  Licensed under the Apache License, Version 2.0 (the "License");
' **  you may not use this file except in compliance with the License.
' **  You may obtain a copy of the License at
' **  
' **    http://www.apache.org/licenses/LICENSE-2.0
' **  
' **  Unless required by applicable law or agreed to in writing, software
' **  distributed under the License is distributed on an "AS IS" BASIS,
' **  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
' **  See the License for the specific language governing permissions and
' **  limitations under the License.
' ** 
' ******************************************************************************


Namespace YahooManaged.Finance.API

    ''' <summary>
    ''' Provides methods for downloading technical analysing chart images.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ChartDownload
        Inherits Base.Download

        ''' <summary>
        ''' Raises if an asynchronous download of an technical analysing chart image completes.
        ''' </summary>
        ''' <param name="sender">The event raising object.</param>
        ''' <param name="ea">The results of the asynchronous download.</param>
        ''' <remarks></remarks>
        Public Event AsyncDownloadCompleted(ByVal sender As Base.Download, ByVal ea As ChartDownloadCompletedEventArgs)

        Friend ReadOnly mFinanceHelper As New FinanceHelper
        Private mOptions As New ChartDownloadOptions

        ''' <summary>
        ''' Gets or sets the chart image download options.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>By setting null/Nothing, a default instance will be setted and used for downloading.</remarks>
        Public Property Options() As ChartDownloadOptions
            Get
                Return mOptions
            End Get
            Set(ByVal value As ChartDownloadOptions)
                mOptions = value
            End Set
        End Property

        ''' <summary>
        ''' Downloads a chart image.
        ''' </summary>
        ''' <param name="managedID">The managed ID of the stock</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Download(ByVal managedID As IID) As Base.StreamResponse
            If managedID Is Nothing Then Throw New ArgumentNullException("managedID", "The passed ID is null.")
            Return Me.Download(managedID.ID)
        End Function
        ''' <summary>
        ''' Downloads a chart image.
        ''' </summary>
        ''' <param name="unmanagedID">The unmanaged ID of the stock</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Download(ByVal unmanagedID As String) As Base.StreamResponse
            If unmanagedID = String.Empty Then Throw New ArgumentNullException("unmanagedID", "The passed ID is empty.")
            Return MyBase.DownloadStream(Me.DownloadURL(unmanagedID, New ChartDownloadOptions(mOptions)))
        End Function

        ''' <summary>
        ''' Starts an asynchronous download of an chart image.
        ''' </summary>
        ''' <param name="managedID">The managed ID of the stock</param>
        ''' <param name="userArgs">Individual user argument</param>
        ''' <remarks></remarks>
        Public Overloads Sub DownloadAsync(ByVal managedID As IID, Optional ByVal userArgs As Object = Nothing)
            If managedID Is Nothing Then Throw New ArgumentNullException("managedID", "The passed ID is null.")
            Me.DownloadAsync(managedID.ID, userArgs)
        End Sub
        ''' <summary>
        ''' Starts an asynchronous download of an chart image.
        ''' </summary>
        ''' <param name="unmanagedID">The unmanaged ID of the stock</param>
        ''' <param name="userArgs">Individual user argument</param>
        ''' <remarks></remarks>
        Public Overloads Sub DownloadAsync(ByVal unmanagedID As String, Optional ByVal userArgs As Object = Nothing)
            If unmanagedID = String.Empty Then Throw New ArgumentNullException("unmanagedID", "The passed ID is empty.")
            Dim args As New AsyncDownloadArgs(New ChartDownloadOptions(mOptions), unmanagedID, userArgs)
            Dim url = Me.DownloadURL(args.ID, args.Options)
            MyBase.DownloadStreamAsync(url, args)
        End Sub

        ''' <summary>
        ''' Default constructor
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
        End Sub

        Private Sub DownloadAsync_Completed(ByVal sender As Base.Download, ByVal e As Base.StreamDownloadCompletedEventArgs) Handles MyBase.AsyncStreamDownloadCompleted
            If e IsNot Nothing AndAlso e.UserArgs IsNot Nothing AndAlso TypeOf e.UserArgs Is AsyncDownloadArgs Then
                Dim dlArgs As AsyncDownloadArgs = DirectCast(e.UserArgs, AsyncDownloadArgs)
                Dim args As New ChartDownloadCompletedEventArgs(dlArgs.UserArgs, e.Response, dlArgs.ID, dlArgs.Options)
                RaiseEvent AsyncDownloadCompleted(Me, args)
            End If
        End Sub

        Private Function DownloadURL(ByVal id As String, ByVal options As ChartDownloadOptions) As String
            Dim url As New Text.StringBuilder
            url.Append("http://")
            With options
                url.Append("chart.finance.yahoo.com/")
                If .SimplifiedImage Then : url.Append("t?")
                Else : url.Append("z?")
                End If
                url.Append("s=")
                url.Append(mHelper.CleanYqlParam(mFinanceHelper.CleanIndexID(id)))

                If .SimplifiedImage Then
                    url.Append("&width=" & .ImageWidth.ToString)
                    url.Append("&height=" & .ImageHeight.ToString)
                Else
                    url.Append("&t=")
                    url.Append(mFinanceHelper.GetChartTimeSpan(.TimeSpan))
                    url.Append("&z=")
                    url.Append(mFinanceHelper.GetChartImageSize(.ImageSize))
                    url.Append("&q=")
                    url.Append(mFinanceHelper.GetChartType(.Type))
                    url.Append("&l=")
                    url.Append(mFinanceHelper.GetChartScale(.Scale))
                    If .MovingAverages.Count > 0 Or .ExponentialMovingAverages.Count > 0 Or .TechnicalIndicators.Count > 0 Then
                        url.Append("&p=")
                        For Each ma As MovingAverageInterval In .MovingAverages
                            url.Append("m"c)
                            url.Append(mFinanceHelper.GetMovingAverageInterval(ma))
                            url.Append(","c)
                        Next
                        For Each ma As MovingAverageInterval In .ExponentialMovingAverages
                            url.Append("e"c)
                            url.Append(mFinanceHelper.GetMovingAverageInterval(ma))
                            url.Append(","c)
                        Next
                        For Each ti As TechnicalIndicator In .TechnicalIndicators
                            url.Append(mFinanceHelper.GetTechnicalIndicatorsI(ti))
                        Next
                    End If
                    If .TechnicalIndicators.Count > 0 Then
                        url.Append("&a=")
                        For Each ti As TechnicalIndicator In .TechnicalIndicators
                            url.Append(mFinanceHelper.GetTechnicalIndicatorsII(ti))
                        Next
                    End If
                    If .ComparingIDs.Count > 0 Then
                        url.Append("&c=")
                        For Each csid As String In .ComparingIDs
                            url.Append(mHelper.CleanYqlParam(mFinanceHelper.CleanIndexID(csid)))
                            url.Append(","c)
                        Next
                    End If
                    If .Culture Is Nothing Then
                        .Culture = Culture.DefaultCultures.UnitedStates_English
                    End If
                End If
                url.Append(mHelper.CultureToParameters(.Culture))
            End With
            Return url.ToString
        End Function

        Private Class AsyncDownloadArgs
            Inherits MaasOne.Base.DownloadEventArgs
            Public ID As String
            Public Options As ChartDownloadOptions
            Public Sub New(ByVal opt As ChartDownloadOptions, ByVal id As String, ByVal userArgs As Object)
                MyBase.New(userArgs)
                Me.ID = id
                Me.Options = opt
            End Sub
        End Class

    End Class

    ''' <summary>
    ''' Provides information and response of an asynchronous chart image download.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ChartDownloadCompletedEventArgs
        Inherits Base.DownloadCompletedEventArgs

        Private mID As String = String.Empty
        Private mOptions As ChartDownloadOptions

        ''' <summary>
        ''' Gets the ID of the chart.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ID() As String
            Get

                Return mID
            End Get
        End Property
        ''' <summary>
        ''' Gets the used chart download options.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Options() As ChartDownloadOptions
            Get
                Return mOptions
            End Get
        End Property
        Public Overloads ReadOnly Property Response() As Base.StreamResponse
            Get
                Return DirectCast(MyBase.Response, Base.StreamResponse)
            End Get
        End Property

        Friend Sub New(ByVal userArgs As Object, ByVal resp As Base.StreamResponse, ByVal id As String, ByVal opt As ChartDownloadOptions)
            MyBase.New(userArgs, resp)
            mID = id
            mOptions = opt
        End Sub

    End Class

    ''' <summary>
    ''' Provides properties for setting options of chart download.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ChartDownloadOptions

        Private mSimplifiedImage As Boolean = False
        Private mImageWidth As Integer = 300
        Private mImageHeight As Integer = 180
        Private mImageSize As ChartImageSize = ChartImageSize.Middle
        Private mTimeSpan As ChartTimeSpan = ChartTimeSpan.c1D
        Private mType As ChartType = ChartType.Line
        Private mScale As ChartScale = ChartScale.Logarithmic
        Private mMovingAverages As New List(Of MovingAverageInterval)
        Private mEMovingAverages As New List(Of MovingAverageInterval)
        Private mTechnicalIndicators As New List(Of TechnicalIndicator)
        Private mComparingIDs As New List(Of String)
        Private mCulture As Culture = Nothing

        ''' <summary>
        ''' Gets or sets the used culture for scale descriptions. Can only be used with Server [USA].
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Culture() As Culture
            Get
                Return mCulture
            End Get
            Set(ByVal value As Culture)
                mCulture = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the width of the image.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ImageWidth As Integer
            Get
                Return mImageWidth
            End Get
            Set(ByVal value As Integer)
                mImageWidth = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the height of the image
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ImageHeight As Integer
            Get
                Return mImageHeight
            End Get
            Set(ByVal value As Integer)
                mImageHeight = value
            End Set
        End Property
        ''' <summary>
        ''' Gets a bool value if the image is simplified (1 day period; only ImageWidth, ImageHeight and Culture options available; Other options are not available)
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property SimplifiedImage() As Boolean
            Get
                Return mSimplifiedImage
            End Get
            Set(ByVal value As Boolean)
                mSimplifiedImage = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the size of the image (only available if SimplifiedImage = FALSE)
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ImageSize As ChartImageSize
            Get
                Return mImageSize
            End Get
            Set(ByVal value As ChartImageSize)
                mImageSize = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the span of the reviewed period.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property TimeSpan() As ChartTimeSpan
            Get
                Return mTimeSpan
            End Get
            Set(ByVal value As ChartTimeSpan)
                mTimeSpan = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the chart type of the image.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Type() As ChartType
            Get
                Return mType
            End Get
            Set(ByVal value As ChartType)
                mType = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the scaling of the image.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Scale() As ChartScale
            Get
                Return mScale
            End Get
            Set(ByVal value As ChartScale)
                mScale = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the list of moving average indicators.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property MovingAverages() As List(Of MovingAverageInterval)
            Get
                Return mMovingAverages
            End Get
            Set(ByVal value As List(Of MovingAverageInterval))
                mMovingAverages = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the list of exponential moving average indicators.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ExponentialMovingAverages() As List(Of MovingAverageInterval)
            Get
                Return mEMovingAverages
            End Get
            Set(ByVal value As List(Of MovingAverageInterval))
                mEMovingAverages = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the list of technical indicators.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property TechnicalIndicators() As List(Of TechnicalIndicator)
            Get
                Return mTechnicalIndicators
            End Get
            Set(ByVal value As List(Of TechnicalIndicator))
                mTechnicalIndicators = value
            End Set
        End Property
        ''' <summary>
        ''' Gets the ID list of all compared stocks/indices.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ComparingIDs() As List(Of String)
            Get
                Return mComparingIDs
            End Get
            Set(ByVal value As List(Of String))
                mComparingIDs = value
            End Set
        End Property

        ''' <summary>
        ''' Default constructor
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
            mCulture = Culture.DefaultCultures.UnitedStates_English
        End Sub
        Friend Sub New(ByVal original As ChartDownloadOptions)
            If original IsNot Nothing Then
                With original
                    mSimplifiedImage = .SimplifiedImage
                    mImageWidth = .ImageWidth
                    mImageHeight = .ImageHeight
                    mImageSize = .ImageSize
                    mTimeSpan = .TimeSpan
                    mType = .Type
                    mScale = .Scale
                    mCulture = .Culture
                    For Each ma In .MovingAverages
                        mMovingAverages.Add(ma)
                    Next
                    For Each ema In .ExponentialMovingAverages
                        mEMovingAverages.Add(ema)
                    Next
                    For Each ti In .TechnicalIndicators
                        mTechnicalIndicators.Add(ti)
                    Next
                    For Each id In .ComparingIDs
                        mComparingIDs.Add(id)
                    Next
                End With
            End If
        End Sub

    End Class

End Namespace

